getmetadata <- function(vname="", dataset.name=dsn) {
  
  #   Args: vname, dataset.name
  #  Value: For non-NULL vname, list of metadata for vname
  #         For vname="", list of metadata for dataset

  if (!exists("dsn")) {
    stop("Dataset name 'dsn' is not defined")
  }
  
  if (vname == "") {
    # Check that metadata table exists
    path <- paste(dataset.name, ".metadata/metadata.txt", sep="")
    if (!file.exists(path)) {
      stop(paste(path, " not found", sep=""))
    }
    # Read metadata table and return list of values
    mdt <- as.matrix(read.table(path, header=TRUE))
    metadata <- as.list(mdt[, 2])
    names(metadata) <- mdt[, 1]
    metadata
  }
  
  if (vname != "") {
    # Read variable table
    vtpath <- paste(dataset.name, ".metadata/variables.txt", sep="")
    vt <- as.matrix(read.table(vtpath, header=TRUE, stringsAsFactors=FALSE))
    
    # Get vname, cbname, uname and vref from variable table
    if (!is.element(vname, vt[, "vname"])) {
      stop(paste("\"", vname, "\" not found in \"", vtpath, "\"", sep=""))
    }
    rownum <- (1:dim(vt)[1])[vt[,"vname"] == vname]
    vline <- as.character(vt[rownum, ])  # vname, cbname, uname, vref
    metadata <- as.list(vline)
    names(metadata) <- colnames(vt)
    
    # Get codes, short values (and long values, if any) from codebook file
    cbpath <- paste(dataset.name, ".codebooks/", metadata$cbname, sep="")
    if (!file.exists(cbpath)) {
      stop(paste("\"", cbpath, "\" not found", sep=""))
    }
    lines <- readLines(cbpath)
    cbt <- NULL
    for (i in 1:length(lines)) {
      cbt <- rbind(cbt, strsplit(lines[i], split=";")[[1]])
    }
    if (dim(cbt)[2] == 2) {
      codebook <- list(codes=cbt[, 1], vshort=cbt[, 2])
    }
    if (dim(cbt)[2] == 3) {
      codebook <- list(codes=cbt[, 1], vshort=cbt[, 2], vlong=cbt[, 3])
    }
    metadata <- c(metadata, codebook)
  }
  
  metadata
  
}